#include "function.h"
#include "plus.h"
#include "minus.h"
#include "mult.h"
#include "div.h"
#include "const.h"
#include "var.h"
#include <iostream>


Function::Function (std::string str)
	: f_(str)
{}

Function::Function (Function * f)
	: f_(f->f_)
{}

Function::Function ()
{}

double Function::value (double x){
    size_t i = 0;
    double result;
    bool found = false;
    Function * res;
    i = f_.find('+');
    if (i != std::string::npos){                                                                                                     	
		res = new Plus ( new Function ( f_.substr(0, i) ), new Function ( f_.substr(i+1) ) );
    	found = true;
    }
    
    i = f_.find('-');    
    if (i != std::string::npos && !found ){                                                                                                    	
		res = new Minus ( new Function ( f_.substr(0, i) ), new Function ( f_.substr(i+1) ) );
    	found = true;
    }
    
    i = f_.find('*');
    if (i != std::string::npos && !found ){
		res = new Mult(new Function ( f_.substr(0, i) ), new Function ( f_.substr(i+1) ));
    	found = true;
    }

    i = f_.find('/');
    if (i != std::string::npos && !found ){                                                                                                     	
		res = new Div ( new Function ( f_.substr(0, i) ), new Function ( f_.substr(i+1) ) );
    	found = true;
    }

    i = f_.find('x');
    if (i != std::string::npos && !found ){
    	res = new Variable ();
    	found = true;
    }
   
    if (f_.length() > 0 && !found ){
    	double a = 0;
		size_t pos = f_.find('.');
		for (size_t i = 0; i != std::min(pos, f_.length()); ++i){
			a = a * 10 + f_[i] - '0';
		}
		if (pos == std::string::npos){
			res = new Const (a);
		}else{
			double k = 10;
			for (size_t i = pos + 1; i != f_.length(); ++i){
				a += (f_[i] - '0')/k;
				k *= 10;
			}
	   		res = new Const (a);
		}
    }
    result = res -> value(x);
    delete res;
	return result;
}

bool Function::solve (double a, double b, double eps, double & result){
	if (value(a) * value(b) > 0){
		return false;
	}
	double s = 0;
	while (b - a > eps){
		s = (a + b) / 2;		
		if (value(a) * value(s) > 0){
			a = s;
		}else{
			b = s;
		}
	}
	result = s;
	return true;
}


void Function::integrate(double a, double b, double h, double & result){
	int n = (int) ((b - a) / h);
	result += value(a) + value(b);
	double temp = 0;
	for (size_t i = 1; i <= n; i+=2){
		temp += value(a + h * i);
	}
	result += 4 * temp;
	temp = 0;
	for (size_t i = 2; i <= n; i+=2){
		temp += value(a + h * i);
	}
	result += 2 * temp;
	result *= (b - a) / (3 * n);
}
